const { CONFIG, whitelistWords } = require("../config");
const { globSync } = require("glob");
const { readFileSync, writeFileSync, existsSync } = require("node:fs");
const vueCompiler = require("@vue/compiler-sfc");
const parser = require("@babel/parser");
const _traverse = require("@babel/traverse");
const _generator = require("@babel/generator");
const GoGoCode = require("gogocode");
const { createHash } = require("crypto");
const base62 = require("base62/lib/ascii");

const parse = parser.parse;
const traverse = _traverse.default;
const generator = _generator.default;

// 获取文件列表
function getFileList(fileType) {
  if (Array.isArray(fileType)) {
    logInfo("开始获取文件列表,文件类型为: " + fileType.join(','));
    return fileList = CONFIG.SRC_DIR.map(dir => globSync(`${dir}/**/*.{${fileType.join(",")}}`)).flat();
  }
  logInfo("开始获取文件列表,文件类型为: " + fileType);
  return fileList = CONFIG.SRC_DIR.map(dir => globSync(`${dir}/**/*.${fileType}`)).flat();
}

// 获取文件内容
function readFileContent(file) {
  try {
    return readFileSync(file, "utf-8");
  } catch (e) {
    logError("读取文件失败: " + e);
    return "";
  }
}

// 写入JSON文件
function writeJsonFile(path, content) {
  if (!existsSync(path)) {
    writeFileSync(path, "{}", { flag: "w" });
  }
  try {
    writeFileSync(path, JSON.stringify(content, null, 2));
  } catch (e) {
    logError("写入文件失败: " + e);
  }
}


function parseFile(content, file) {
  const ext = file.split(".").pop();
  logInfo("开始处理文件: " + file);
  if (ext === 'vue') {
    return vueCompiler.parse(content);
  } else {
    return parse(content, { sourceType: "module", plugins: ["jsx", "typescript"] });
  }
}



// 日志输出
function logInfo(msg) {
  console.log("[INFO]", msg);
}
// 错误输出
function logError(msg) {
  console.error("[ERROR]", msg);
}
// 判断是否是中文
function isChinese(str) {
  if (whitelistWords.includes(str.trim())) {
    return false
  }
  return CONFIG.CHINESE_REGEX.test(str)
}
// 判断是否包含中文
function hasChinese(str) {
  return str.search(CONFIG.CHINESE_REGEX) > -1
}


// 读取语言包
function readLangObj() {
  try {
    if (!existsSync(CONFIG.LANG_FILE)) {
      writeFileSync(CONFIG.LANG_FILE, "{}", { flag: "w" });
    }
    const langContent = readFileSync(CONFIG.LANG_FILE, "utf-8");
    return JSON.parse(langContent);
  } catch (e) {
    logError("读取语言包失败: " + e);
    return {};
  }
}

// 写入语言包
function writeLangObj(langObj) {
  try {
    writeFileSync(CONFIG.LANG_FILE, JSON.stringify(langObj, null, 2));
  } catch (e) {
    logError("写入语言包失败: " + e);
  }
}

// 生成唯一key
function genKey(str) {
  // 1. 计算SHA-1哈希（160位 → 20字节）
  const hashBuffer = createHash('sha1').update(str).digest();

  // 2. 取前4字节（32位）并转为32位无符号整数
  const truncated = hashBuffer.subarray(0, 4);
  const num = truncated.readUInt32BE();

  // 3. Base62编码压缩为6-8字符
  return base62.encode(num).padStart(6, '0').slice(0, 8);
}

// 属性处理
function handleAttrs(attrs, langObj) {
  attrs.forEach((item) => {
    const attr = item
    const { key, value } = attr;
    const keyContent = key.content || "";
    if (value && value.content) {
      if (["v-", ":", "@"].some((p) => keyContent.startsWith(p))) {
        if (hasChinese(value.content)) {
          try {
            const inlineAst = parse(value.content, { sourceType: "module" });
            traverse(inlineAst, {
              StringLiteral(path) {
                if (isChinese(path.node.value)) {
                  const k = genKey(path.node.value);
                  if (!langObj[k]) {
                    langObj[k] = path.node.value;
                    writeLangObj(langObj);
                  }
                  path.replaceWithSourceString(`${CONFIG.I18N_FUNC}('${k}')`);
                }
              },
            });
            const code = generator(inlineAst).code;
            // 删除行尾分号
            attr.value.content = code.endsWith(";") ? code.slice(0, -1) : code;
          } catch (e) {
            logError("属性表达式解析失败: " + e);
          }
        }
      } else {
        if (isChinese(value.content)) {
          const k = genKey(value.content);
          if (!langObj[k]) {
            langObj[k] = value.content;
            writeLangObj(langObj);
          }
          attr.value.content = `${CONFIG.I18N_FUNC}('${k}')`;
          attr.key.content = `:${keyContent}`;
        }
      }
    }
  });
}
// 文本节点处理
function handleTextNode(item, langObj) {
  if (item.nodeType === "text") {
    const value = item.content.value;
    const text = value.content.trim();
    if (text.includes("{{") && text.includes("}}")) {
      value.content = text.replace(/\{\{[\s\S]*?\}\}/g, (match) => {
        const inlineAst = parse(match.trim().replace(/^{{/, "").replace(/}}$/, ""), { sourceType: "module" });
        traverse(inlineAst, {
          StringLiteral(path) {
            if (isChinese(path.node.value)) {
              const k = genKey(path.node.value);
              if (!langObj[k]) {
                langObj[k] = path.node.value;
                writeLangObj(langObj);
              }
              path.replaceWithSourceString(`${CONFIG.I18N_FUNC}('${k}')`);
            }
          },
        });
        const code = generator(inlineAst).code;
        return `{{${code.endsWith(";") ? code.slice(0, -1) : code}}}`;
      }).replace(CONFIG.CHINESE_REGEX_G, (match) => {
        const k = genKey(match);
        if (!langObj[k]) {
          langObj[k] = match;
          writeLangObj(langObj);
        }
        return `{{${CONFIG.I18N_FUNC}('${k}')}}`;
      });
    } else {
      if (isChinese(value.content)) {
        const text = value.content.trim();
        const k = genKey(text);
        if (!langObj[k]) {
          langObj[k] = text;
          writeLangObj(langObj);
        }
        value.content = `{{${CONFIG.I18N_FUNC}('${k}')}}`;
      }
    }
  }
}
// JS/TS字符串处理
function handleStringLiteral(path, langObj, prefix = 'this.') {
  if (isChinese(path.node.value)) {
    const k = genKey(path.node.value);
    if (!langObj[k]) {
      langObj[k] = path.node.value;
      writeLangObj(langObj);
    }
    path.replaceWithSourceString(`${prefix}${CONFIG.I18N_FUNC}('${k}')`);
  }
}

function processTemplate(content) {
  const langObj = readLangObj();
  const templateAst = GoGoCode(content, { parseOptions: { html: true, attachComment: true } });
  // 如果没有中文，直接返回
  if (!hasChinese(content)) {
    return content;
  }
  templateAst.find(["<$_$></$_$>", "<$_$ />"]).each((node) => {
    const attrs = node.attr("content.attributes");
    if (Array.isArray(attrs) && attrs.length) {
      handleAttrs(attrs, langObj);
    }
    const children = node.attr("content.children");
    if (Array.isArray(children) && children.length) {
      children.forEach((item) => {
        handleTextNode(item, langObj);
      });
    }
  });
  const code = templateAst.generate();
  return code;
}

function isInDataOrProps(path, filePath) {
  const file = filePath.replace(/\\/g, '/')
  const target = path.findParent((pt) => {
    return pt.node.key?.name === 'props' || pt.node.key?.name === 'data'
  })
  if (target) {
    if (!existsSync(CONFIG.LOG_FILE)) {
      writeFileSync(CONFIG.LOG_FILE, "{}", { flag: "w" });
    }
    const content = JSON.parse(readFileSync(CONFIG.LOG_FILE, "utf-8"));
    if (path.node.value && hasChinese(path.node.value)) {
      if (!content[file]) {
        content[file] = []
      }
      if (!content[file].includes(path.node.value)) {
        content[file].push(path.node.value)
      }
    }
    try {
      writeFileSync(CONFIG.LOG_FILE, JSON.stringify(content, null, 2));
    } catch (e) {
      logError("写入文件失败: " + e);
    }
  }
  return !!target
}

function isInUni(path) {
  const target = path.findParent((pt) => {
    return pt.node?.type === 'CallExpression' && pt.node.callee?.object?.name === 'uni'
  })
  return !!target
}

function isInConsole(path) {
  const target = path.findParent((pt) => {
    return pt.node?.type === 'CallExpression' && pt.node.callee?.object?.name === 'console'
  })
  return !!target
}

function processJs(content, file) {
  const langObj = readLangObj();
  const ast = parse(content, { sourceType: "module", plugins: ["jsx", "typescript"] });
  // writeJsonFile("./script/ast.json", ast);
  traverse(ast, {
    StringLiteral(path) {
      if (!isInDataOrProps(path, file) && !isInConsole(path)) {
        handleStringLiteral(path, langObj, isInUni(path) ? 'self.' : 'this.');
      }
    },
  });
  return generator(ast).code;
}


module.exports = {
  getFileList,
  logInfo,
  logError,
  isChinese,
  hasChinese,
  readLangObj,
  writeLangObj,
  writeJsonFile,
  genKey,
  readFileContent,
  parseFile,
  processTemplate,
  processJs
}